#!/bin/sh
#
# $FreeBSD$
#
# I want to rewrite this in python. That is all.
#

# PROVIDE: ix-kinit
# REQUIRE: kdc
# REQUIRE: ix-pre-samba
# REQUIRE: ntpd

. /etc/rc.freenas

kerberos_get_principal()
{
	/usr/bin/klist 2>/dev/null|egrep '^ +Principal'|awk '{ print $2 }'
}

kerberos_principal_check()
{
	local principal="${1}"
	local krb_principal="$(kerberos_get_principal)"

	if [ -z "${principal}" -o -z "${krb_principal}" ]
	then
		return 1
	fi

	principal="$(echo "${principal}"|tr a-z A-Z)"
	krb_principal="$(echo "${krb_principal}"|tr a-z A-Z)"

	local res=1
	if [ "${principal}" = "${krb_principal}" ]
	then
		res=0
	fi

	return ${res}
}

kerberos_start_activedirectory()
{
	local res=1
	local pwfile
	local timeout=60

	AD_init

	local realm="$(AD_get ad_krb_realm)"
	local bindname="$(AD_get ad_bindname)"
	local bindpw="$(AD_get ad_bindpw)"
	local domainname="$(AD_get ad_domainname)"
	local keytab_principal="$(AD_get ad_keytab_principal)"

	if [ -n "${keytab_principal}" ]
	then
		local res=0
		local keytab_file="$(AD_get ad_keytab_file)"

		AD_log "kerberos_start: /usr/bin/kinit --renewable -t ${keytab_file} -k ${keytab_principal}"
		/usr/bin/kinit -t "${keytab_file}" --renewable -k "${keytab_principal}"
		if [ "$?" != "0" ]
		then
			res=1
			break
		fi
		res=0

		local ok="Failed"
		if [ "${res}" = "0" ]
		then
			ok="Successful"
		fi

		AD_log "kerberos_start: ${ok}"
		rm -f "${pwfile}"

		if [ "${res}" != 0 ]
		then
			return 1
		fi

		i=0
		timeout="$(AD_get ad_timeout)"
		while [ "${i}" -lt "${timeout}" ]
		do
			/usr/bin/klist -t
			if [ "$?" = "0" ]
			then
				break
			fi

			sleep 1
			: $(( i += 1 ))
		done

	elif [ -n "${realm}" -a -n "${bindname}" -a -n "${bindpw}" ]
	then
		local principal="${bindname}@${realm}"

		pwfile="$(mktemp /tmp/tmp.XXXXXXXX)"
		echo -n "${bindpw}" > ${pwfile}

		AD_log "kerberos_start: /usr/bin/kinit --renewable " \
			"--password-file=${pwfile} ${principal}"
		timeout_wait ${timeout} /usr/bin/kinit --renewable \
			--password-file="${pwfile}" "${principal}"
		res=$?

		local ok="Failed"
		if [ "${res}" = "0" ]
		then
			ok="Successful"
		fi

		AD_log "kerberos_start: ${ok}"
		rm -f "${pwfile}"

		if [ "${res}" != 0 ]
		then
			return 1
		fi

		i=0
		timeout="$(AD_get ad_timeout)"
		while [ "${i}" -lt "${timeout}" ]
		do
			/usr/bin/klist -t
			if [ "$?" = "0" ]
			then
				break
			fi

			sleep 1
			: $(( i += 1 ))
		done
	fi

	return ${res}
}

kerberos_status_activedirectory()
{
	local res=1

	AD_init

	local domainname=$(AD_get ad_domainname)

	domainname=$(echo "${domainname}"|tr a-z A-Z)
	if [ -n "${domainname}" ]
	then

		AD_log "kerberos_status: klist -t"
		/usr/bin/klist -t
		res=$?

		local ok="Failed"
		if [ "${res}" = "0" ]
		then
			ok="Successful"
		fi

		AD_log "kerberos_status: ${ok}"
	fi

	return ${res}
}

kerberos_start_ldap()
{
	local res=1
	local pwfile
	local timeout=60

	LDAP_init

	local realm=$(LDAP_get ldap_krb_realm)
	local binddn="$(LDAP_get ldap_binddn)"
	local bindpw="$(LDAP_get ldap_bindpw)"
	local hostname="$(LDAP_get ldap_hostname)"
	local keytab_principal="$(LDAP_get ldap_keytab_principal)"

	if [ -n "${keytab_principal}" ]
	then
		local res=0
		local keytab_file="$(LDAP_get ldap_keytab_file)"

		LDAP_log "kerberos_start: /usr/bin/kinit --renewable -t ${keytab_file} -k ${keytab_principal}"
		/usr/bin/kinit -t "${keytab_file}" \
			--renewable -k "${keytab_principal}"
		if [ "$?" != "0" ]
		then
			res=1
			break
		fi
		res=0

		local ok="Failed"
		if [ "${res}" = "0" ]
		then
			ok="Successful"
		fi

		LDAP_log "kerberos_start: ${ok}"
		rm -f "${pwfile}"

		i=0
		timeout="$(LDAP_get ldap_timeout)"
		while [ "${i}" -lt "${timeout}" ]
		do
			/usr/bin/klist -t
			if [ "$?" = "0" ]
			then
				break
			fi

			sleep 1
			: $(( i += 1 ))
		done

	elif [ -n "${realm}" -a -n "${binddn}" -a -n "${bindpw}" ]
	then
		local uid="$(LDAP_get_binddn_uid)"
		if [ -z "${uid}" ]
		then
			LDAP_log "kerberos_start: unable to determine uid"
		fi

		local principal="${uid}@${realm}"

		pwfile="$(mktemp /tmp/tmp.XXXXXXXX)"
		echo -n "${bindpw}" > ${pwfile}

		LDAP_log "kerberos_start: /usr/bin/kinit --renewable " \
			"--password-file=${pwfile} ${principal}"
		timeout_wait ${timeout} /usr/bin/kinit --renewable \
			--password-file="${pwfile}" "${principal}"
		res=$?

		local ok="Failed"
		if [ "${res}" = "0" ]
		then
			ok="Successful"
		fi

		LDAP_log "kerberos_start: ${ok}"
		rm -f "${pwfile}"

		if [ "${res}" != 0 ]
		then
			return 1
		fi

		i=0
		timeout="$(LDAP_get ldap_timeout)"
		while [ "${i}" -lt "${timeout}" ]
		do
			/usr/bin/klist -t
			if [ "$?" = "0" ]
			then
				break
			fi

			sleep 1
			: $(( i += 1 ))
		done
	fi

	return ${res}
}

kerberos_status_ldap()
{
	local res=1

	LDAP_init

	local realm=$(LDAP_get ldap_krb_realm)

	if [ -n "${realm}" ]
	then
		LDAP_log "kerberos_status: klist -t"
		/usr/bin/klist -t
		res=$?

		local ok="Failed"
		if [ "${res}" = "0" ]
		then
			ok="Successful"
		fi

		LDAP_log "kerberos_status: ${ok}"
	fi

	return ${res}
}

kerberos_start()
{
	local res=1

	if dirsrv_enabled activedirectory
	then
		kerberos_start_activedirectory
		res=$?

	elif dirsrv_enabled ldap
	then
		kerberos_start_ldap
		res=$?
	fi

	return ${res}
}

kerberos_status()
{
	local res=1

	if dirsrv_enabled activedirectory
	then
		kerberos_status_activedirectory
		res=$?

	elif dirsrv_enabled ldap
	then
		kerberos_status_ldap
		res=$?
	fi

	return ${res}
}

kerberos_stop()
{
	/usr/bin/kdestroy
}

kerberos_renew()
{
	local ad_enabled=0
	local ldap_enabled=0

	if dirsrv_enabled activedirectory
	then
		ad_enabled=1
	fi
	if dirsrv_enabled ldap
	then
		LDAP_init

		local realm=$(LDAP_get ldap_krb_realm)
		local keytab_principal="$(LDAP_get ldap_keytab_principal)"

		if [ -z "${realm}" -a -z "${keytab_principal}" ]
		then
			return
		fi

		ldap_enabled=1
	fi

	if [ "${ad_enabled}" = "0" -a "${ldap_enabled}" = "0" ]
	then
		return
	fi

	local klist_out="$(/usr/bin/mktemp /tmp/XXXXXX)"

	/usr/bin/klist -v > "${klist_out}"

	local krbtgt_ticket=false
	local auth_time=
	local end_time=
	local renew_until=
	local cur_time=

	local time_regex='[a-zA-Z]{3,4} +[0-9]{1,2} +[0-9]{2}:[0-9]{2}:[0-9]{2} +[0-9]{4}'

	exec 3<& 0
	exec 0< "${klist_out}"
	while read line
	do
		if [ -z "${line}" ]; then continue; fi

		if echo "${line}"|egrep -q '^Server: +' &&
			echo "${line}"|egrep -q '^Server: +krbtgt\/.+'
		then
			krbtgt_ticket=true
		elif echo "${line}"|egrep -q '^Server: +' &&
			! echo "${line}"|egrep -iq '^Server: +krbtgt\/.+'
		then
			krbtgt_ticket=false
		fi

		if ${krbtgt_ticket} && echo "${line}"|egrep -iq '^Auth time: +'
		then
			strtime="$(echo "${line}"|sed -E 's|^(Auth time: +)||I')"
			strtime="$(echo "${strtime}"|sed -E 's|^(${time_regex})|\1|')"
			if [ -z "${strtime}" ]; then continue; fi

			auth_time="$(date -j -f '%b %d %H:%M:%S %Y' \
				"${strtime}" '+%s' 2>/dev/null)"

		elif ${krbtgt_ticket} && echo "${line}"|egrep -iq '^End time: +'
		then
			strtime="$(echo "${line}"|sed -E 's|^(End time: +)||I')"
			strtime="$(echo "${strtime}"|sed -E 's|^(${time_regex})|\1|')"
			if [ -z "${strtime}" ]; then continue; fi

			end_time="$(date -j -f '%b %d %H:%M:%S %Y' \
				"${strtime}" '+%s' 2>/dev/null)"

		elif ${krbtgt_ticket} && echo "${line}"|egrep -iq '^Renew till: +'
		then
			strtime="$(echo "${line}"|sed -E 's|^(Renew till: +)||I')"
			strtime="$(echo "${strtime}"|sed -E 's|^(${time_regex})|\1|')"
			if [ -z "${strtime}" ]; then continue; fi

			renew_until="$(date -j -f '%b %d %H:%M:%S %Y' \
				"${strtime}" '+%s' 2>/dev/null)"
		fi

		if [ -n "${auth_time}" -a -n "${end_time}" -a -n "${renew_until}" ]
		then
			break
		fi
	done
	exec 0<& 3
	rm -f "${klist_out}"

	if [ -z "${auth_time}" -o -z "${end_time}" -o -z "${renew_until}" ]
	then
		kerberos_start
		return $?
	fi

	local cur_time="$(date -j -f '%b %d %H:%M:%S %Y' \
		"$(date -j '+%b %d %H:%M:%S %Y')" '+%s' 2>/dev/null)"

	#
	# 5 minute fudge factor
	#
	: $(( cur_time +=  300 ))
	if [ "${cur_time}" -lt "${end_time}" -a "${cur_time}" -lt "${renew_until}" ]
	then
		/usr/bin/kinit -R
	else
		kerberos_start
	fi
}

name="ix-kinit"
start_cmd='kerberos_start'
status_cmd='kerberos_status'
stop_cmd='kerberos_stop'
renew_cmd="kerberos_renew"
extra_commands="renew"

load_rc_config $name
run_rc_command "$1"
